package benchmark;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;


import utils.Tools;
import utils.Tools.OutputType;

public class Falsesharing extends AbstractBenchmarkMT {

	private class FSArrayCallable implements Callable<Long> {
		
		long[] array;
		int position;
		
		public FSArrayCallable(long[] array, int position) {
			this.array = array;
			this.position = position;
		}
		
		@Override
		public Long call() throws Exception {
			long counter = iterTimes;
			while (counter-- > 0) {
				array[position] += counter + position;
			}
			// return sum of the entire array to avoid optimize
			long sum = 0;
			for (int i = 0; i < array.length; i++) {
				sum += array[i];
			}
//			System.out.format("p:%d, v:%d\n", position, array[position]);
			return array[position];
		}
		
	}
	

	private final static String STRIDE = "stride";

	private final static String ITERATION_TIMES = "itimes";

	public Falsesharing(String[] args) throws Exception {
		super(args);

		this.argReadme.put(STRIDE, "Stride.");
		this.argReadme.put(ITERATION_TIMES, "Iteration times for accessing the data.");

		data = Tools.newMem(getThreadNum() * getArg(STRIDE));
		
		iterTimes = getArg(ITERATION_TIMES);

		threadNum = getThreadNum();
		
		stride = getArg(STRIDE);
	}
	
	private volatile long[] data;
	
	private long iterTimes;
	
	private long threadNum;
	
	private long stride;


	@Override
	protected List<Callable<Long>> initRunnables() {
		List<Callable<Long>> l = new ArrayList<Callable<Long>>();
		for (int i = 0; i < threadNum; i++) {
			l.add(new FSArrayCallable(data, (int) (stride * i)));
		}
		return l;
	}

	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		Tools.output(Arrays.toString(args), OutputType.DEBUG);
		Falsesharing b = new Falsesharing(args);
		b.run();

	}


}
